package org.jproxy.json;

import java.util.ArrayList;
import java.util.List;

import org.jproxy.json.JSONObject.Type;


public class JSONParser
{

	public JSONObject parse(String json)
	{
		TokenParser parser = new TokenParser(new StringBuilder(json));
		return parseJSON(parser.nextToken(), parser);
	}

	private JSONObject parseJSON(String token, TokenParser parser)
	{
		if("{".equals(token))
			return parseObject(parser);
		else if("[".equals(token))
			return parseArray(parser);
		else
			return parseValue(token, parser);
	}

	private JSONObject parseObject(TokenParser parser)
	{
		String token = null;
		List<JSONAttribute> attList = new ArrayList<JSONAttribute>();
		while(!"}".equals((token = parser.nextToken())) && token != null)
		{
			if(isQuote(token))
				token = parser.nextToken();
			String name = token;
			token = parser.nextToken();
			if(isQuote(token))
				token = parser.nextToken();
			if(":".equals(token))
				attList.add(new JSONAttribute(name, parseJSON(parser.nextToken(), parser)));
			token = parser.nextToken();
		}
		return new ComplexJSONObject(attList);
	}

	private JSONObject parseArray(TokenParser parser)
	{
		String token = null;
		List<JSONObject> objList = new ArrayList<JSONObject>();
		while(!"]".equals((token = parser.nextToken())) && token != null)
		{
			if(",".equals(token))
				token = parser.nextToken();
			objList.add(parseValue(token, parser));
		}
		return new ArrayJSONObject(objList);
	}

	private JSONObject parseValue(String token, TokenParser parser)
	{
		if(isQuote(token))
			return parseValueQuote(parser, token);
		Type type = "true".equals(token) || "false".equals(token) ? Type.BOOLEAN : "null".equals(token) ? Type.VOID : Type.NUMBER;
		return new SimpleJSONObject("", token, type);
	}

	private boolean isQuote(String token)
	{
		return "\"".equals(token) || "'".equals(token);
	}

	private JSONObject parseValueQuote(TokenParser parser, String quote)
	{
		String value = parser.nextToken();
		String end = parser.nextToken();
		if(quote.equals(end))
			return new SimpleJSONObject("", value, Type.STRING);
		throw new IllegalArgumentException(new StringBuilder("JSON error: expected ").append(quote).append(" but found ").append(end).toString());
	}

}
